Skip to content

feat: expose device-based consent APIs in React Native bridge#351

Merged
denischilik merged 10 commits into
mainfrom
feat/device-based-consent
Jun 25, 2026
Merged

feat: expose device-based consent APIs in React Native bridge#351
denischilik merged 10 commits into
mainfrom
feat/device-based-consent

Conversation

@denischilik

Copy link
Copy Markdown
Contributor

Add device-level consent state to React Native bridge

Summary

Exposes device-level consent APIs in the React Native wrapper so apps can set, read, and clear device-scoped consent from JavaScript. Native device consent (added in mParticle Apple SDK and android-core) supersedes per-user/MPID consent when set — consent collected before login or across identity changes at checkout is retained on the device.

Bridges to:

  • iOSMParticle.sharedInstance().deviceConsentState (requires mParticle Apple SDK 9.2+ with device consent)
  • AndroidMParticle.getInstance().setDeviceConsentState() / getDeviceConsentState() (requires android-core release with device consent APIs; resolves via [5.79.2, 6.0))

What has changed

  • Added setDeviceConsentState, clearDeviceConsentState, and getDeviceConsentState to the JS API and default export
  • Wired TurboModule/codegen spec, Android MParticleModule, and iOS RNMParticle (old arch + new arch)
  • Reused existing consent map converters on Android; added RCTConvert MPConsentState: and consentStateToDictionary: on iOS

Sample code

import {
  setDeviceConsentState,
  clearDeviceConsentState,
  getDeviceConsentState,
} from 'react-native-mparticle';

// Set device-wide consent (supersedes any per-user consent)
setDeviceConsentState({
  gdpr: {
    data_sharing: {
      consented: true,
      document: 'privacy_policy_v3',
      timestamp: Date.now(),
    },
  },
});

// Clear — reverts to user/MPID-level consent
clearDeviceConsentState();

// Read current device consent
getDeviceConsentState((state) => {
  console.log(state);
});

Testing

  • ./gradlew test and ./gradlew ktlintCheck pass on the Android module

Checklist

  • I have performed a self-review of my own code.
  • I have made corresponding changes to the documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have tested this locally.

Related Android PR: mParticle/mparticle-android-sdk#726

Related iOS PR: mParticle/mparticle-apple-sdk#784 (merged)

Bridge setDeviceConsentState, clearDeviceConsentState, and
getDeviceConsentState to native device consent on iOS and Android.
@denischilik denischilik requested a review from a team as a code owner June 25, 2026 16:47
@cursor

cursor Bot commented Jun 25, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes affect privacy/consent behavior and how timestamps are parsed for GDPR/CCPA; incorrect mapping could mis-report consent, though scope is limited to new device APIs and existing consent converters.

Overview
Adds device-scoped consent to the public JS API via setDeviceConsentState, clearDeviceConsentState, and getDeviceConsentState, wired through the TurboModule spec and native bridges on Android and iOS (old and new architecture). Device consent maps to MParticle device consent on the native SDKs and can override per-user/MPID consent when set.

Introduces a DeviceConsentState type (GDPR purposes + optional CCPA) and shared conversion helpers: Android builds/reads full ConsentState objects and treats empty payloads as clear; iOS adds RCTConvert MPConsentState: and round-trip consentStateToDictionary: for reads.

Consent timestamp handling is tightened on both platforms—Android accepts number or string millis via readConsentTimestampMillis; iOS GDPR/CCPA converters interpret JS timestamps as epoch milliseconds instead of generic NSDate conversion.

Reviewed by Cursor Bugbot for commit ab85cc1. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread android/src/main/java/com/mparticle/react/MParticleModule.kt Outdated
Comment thread ios/RNMParticle/RNMParticle.mm Outdated
Comment thread android/src/main/java/com/mparticle/react/MParticleModule.kt Outdated
Re-export DeviceConsentState from NativeMParticle codegen so
getDeviceConsentState callback matches the TurboModule signature.
Device consent RCT_EXPORT_METHODs call MPConsentState: before the
RCTConvert category is defined later in the file.
- Move old-arch RCT_EXPORT_METHODs into #else block to avoid duplicate
  declarations when New Architecture is enabled.
- Move consentStateToDictionary onto RNMParticle (was wrongly on RCTConvert).
- Use NSDictionary codegen types for new-arch setDeviceConsentState.
Use NSNull in getDeviceConsentState callback when
consentStateToDictionary returns nil for an empty MPConsentState.
Comment thread ios/RNMParticle/RNMParticle.mm
Comment thread android/src/main/java/com/mparticle/react/MParticleModule.kt
Comment thread android/src/main/java/com/mparticle/react/MParticleModule.kt
When gdpr is null or not a map, continue processing ccpa instead of
returning null from convertToConsentState.
MPConsentState and RCT_EXPORT consent paths use MPGDPRConsent/
MPCCPAConsent converters that treated JS timestamps as seconds via
RCTConvert NSDate. Divide by 1000 to match Date.now() and read path.
Assign nil/null when the converted consent state has no GDPR or CCPA
entries, matching clearDeviceConsentState behavior.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a30b9e8. Configure here.

Comment thread ios/RNMParticle/RNMParticle.mm
Read consent timestamps as Number or String on Android so getDeviceConsentState
round-trips correctly. Guard iOS MPConsentState conversion against non-dictionary
GDPR/CCPA values. Fix new arch setDeviceConsentState by converting codegen structs
to NSDictionary before RCTConvert.
Codegen exposes DeviceConsentState.gdpr() as id, not std::optional, so
setDeviceConsentState must not call has_value/value on it.
@denischilik denischilik merged commit 72235e0 into main Jun 25, 2026
11 checks passed
@denischilik denischilik deleted the feat/device-based-consent branch June 25, 2026 21:06
@rokt-releases rokt-releases Bot mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants